import tempfile
import uuid

import cv2
import numpy as np
import logging

from moviepy import *
from tqdm import tqdm  # 用于显示进度条

from VideoHandler.utils.file_utils import download_file, delete_file, get_extension


logger = logging.getLogger('VideoHandler')


def create_slideshow(image_paths, close_clip_list, music_path=None, frame_duration=2.0,
                     frame_rate=30, resolution=None, transition_duration=0.5, transition_type='slide'):

    print(f"找到{len(image_paths)}张图片，开始生成轮播视频...")

    # 计算总帧数和每张图片的帧数
    frames_per_image = int(frame_duration * frame_rate)
    transition_frames = int(transition_duration * frame_rate)

    # 视频编解码器
    fourcc = cv2.VideoWriter_fourcc(*'mp4v')

    temp_video_path = tempfile.gettempdir() + "/" + str(uuid.uuid4()) + '.mp4'

    # 创建视频写入器
    out = cv2.VideoWriter(temp_video_path, fourcc, frame_rate, resolution)

    # 下载所有图片到临时目录
    local_image_paths = []
    for image_path in image_paths:
        image_suffix = get_extension(image_path)

        local_image_path = download_file(image_path, image_suffix)
        local_image_paths.append(local_image_path)

    # 处理第一张图片
    first_img = cv2.imread(local_image_paths[0])
    first_img = cv2.resize(first_img, resolution)
    for _ in range(frames_per_image):
        out.write(first_img)

    # 处理中间图片及过渡效果
    for i in tqdm(range(1, len(local_image_paths)), desc="生成视频帧"):
        prev_img = cv2.imread(local_image_paths[i - 1])
        curr_img = cv2.imread(local_image_paths[i])

        # 调整图片尺寸以适应分辨率
        prev_img = cv2.resize(prev_img, resolution)
        curr_img = cv2.resize(curr_img, resolution)

        if transition_type == "fade":
            # 淡入淡出效果
            for f in range(transition_frames):
                alpha = f / transition_frames
                beta = 1.0 - alpha
                transition_frame = cv2.addWeighted(prev_img, beta, curr_img, alpha, 0)
                out.write(transition_frame)

        elif transition_type == "slide":
            # 由右向左滑动效果
            for f in range(transition_frames):
                # 计算当前帧的偏移量
                offset = int(resolution[0] * (1 - f / transition_frames))

                # 创建过渡帧
                transition_frame = np.zeros_like(prev_img)

                # 左侧显示前一张图片的剩余部分
                if offset > 0:
                    transition_frame[:, :offset] = prev_img[:, -offset:]

                # 右侧显示当前图片的进入部分
                if offset < resolution[0]:
                    transition_frame[:, offset:] = curr_img[:, :-offset]

                out.write(transition_frame)

        elif transition_type == "zoom":
            # 缩放效果
            for f in range(transition_frames):
                # 计算缩放因子
                scale_factor = 1 - (f / transition_frames) * 0.3  # 缩放30%

                # 缩放前一张图片
                prev_h, prev_w = prev_img.shape[:2]
                prev_scaled = cv2.resize(prev_img, (int(prev_w * scale_factor), int(prev_h * scale_factor)))

                # 将缩放后的图片放置在中心
                h, w = prev_img.shape[:2]
                h_scaled, w_scaled = prev_scaled.shape[:2]
                y_offset = (h - h_scaled) // 2
                x_offset = (w - w_scaled) // 2

                transition_frame = np.zeros_like(prev_img)
                transition_frame[y_offset:y_offset + h_scaled, x_offset:x_offset + w_scaled] = prev_scaled

                # 淡入当前图片
                alpha = f / transition_frames
                transition_frame = cv2.addWeighted(transition_frame, 1 - alpha, curr_img, alpha, 0)

                out.write(transition_frame)

        # 显示当前图片
        for _ in range(frames_per_image - transition_frames):
            out.write(curr_img)

    # 释放视频写入器
    out.release()

    # 加载临时视频
    video = VideoFileClip(temp_video_path)

    # 加载音乐
    audio = AudioFileClip(music_path)
    # 调整音乐时长以匹配视频
    if audio.duration < video.duration:
        # 如果音乐太短，重复播放
        num_loops = int(video.duration / audio.duration) + 1
        audio = concatenate_audioclips([audio] * num_loops).subclipped(0, video.duration)
    else:
        # 截取音乐到视频长度
        audio = audio.subclipped(0, video.duration)

    # 设置视频音频
    video = video.with_audio(audio)

    for local_image_path in local_image_paths:
        delete_file(local_image_path)

    gc_clip = {'path': music_path, "clip": audio}
    close_clip_list.append(gc_clip)
    return video